#include "stdafx.h"
#include "UiHandler.h"
#include "../../Common/Interfaces/IPluginManager.h"
#include "../../Common/Interfaces/IEnvironment.h"
#include "../../Common/DetourHelper.h"
#include "../../Common/Exception.h"

IServiceLocator* k_UiHandler::ms_ServiceLocator;

k_UiHandler::k_UiHandler(IServiceLocator& ar_SvLocator)
	: mr_ServiceLocator(ar_SvLocator)
	, mr_PluginsBar_(NULL)
{
	ms_ServiceLocator = &mr_ServiceLocator;

	this->InitializeMainDialog();
	this->LoadApplicationSettings();
}


k_UiHandler::~k_UiHandler()
{
	mr_PluginsBar_ = NULL;
}


void* k_UiHandler::QueryInterface(const GUID& ar_InterfaceGuid)
{
	if (ar_InterfaceGuid == __uuidof(IUiHandler)) 
		return static_cast<IUiHandler*>(this);

	return NULL; 
}


void k_UiHandler::Close()
{
	IUserInterface& lr_Ui = object_cast<IUserInterface>(mr_ServiceLocator);
	lr_Ui.set_Active(false);
}


IServiceLocator& k_UiHandler::get_ServiceLocator()
{
	return mr_ServiceLocator;
}


void k_UiHandler::InitializeMainDialog()
{
	IPluginManager& lr_PluginManager = object_cast<IPluginManager>(mr_ServiceLocator);
	std::vector<IDirect3D9BasePlugin*> lk_Plugins = lr_PluginManager.get_Plugins();

	mr_PluginsBar_ = ::TwNewBar("Plugins");
	TwDefine(" Plugins size='240 200' help='These are the currently available plugins' color='96 0 0' alpha=200 iconifiable=false alwaysbottom=true");

	for (unsigned int i = 0; i < lk_Plugins.size(); ++i)
	{
		USES_CONVERSION;
		std::string ls_ItemText = W2A(lk_Plugins[i]->get_Name().c_str());

		ls_ItemText = W2A(std::wstring(L"Edit " + lk_Plugins[i]->get_Name() + L" options").c_str());
		::TwAddButton(mr_PluginsBar_, ls_ItemText.c_str(), k_UiHandler::ShowPluginCallback, lk_Plugins[i], "");

		ls_ItemText = W2A(std::wstring(lk_Plugins[i]->get_Name() + L"Options").c_str());
		TwBar* lr_PluginBar_ = ::TwNewBar(ls_ItemText.c_str());
		ls_ItemText = std::string(" ") + ls_ItemText + std::string(" hide label='") + std::string(W2A(lk_Plugins[i]->get_Name().c_str())) + std::string(" options' color='64 0 0' alpha=220 size='300 300' iconifiable=false");
		TwDefine(ls_ItemText.c_str());
		mk_PluginDialogs[lk_Plugins[i]] = lr_PluginBar_;
		this->BuildPluginSpecificDialog(lk_Plugins[i], lr_PluginBar_);
	}

	::TwAddSeparator(mr_PluginsBar_, "", "");
	::TwAddButton(mr_PluginsBar_, "Save application settings", k_UiHandler::SaveSettingsDialogCallback, this, "");
	::TwAddButton(mr_PluginsBar_, "Close Walhall options", k_UiHandler::ClosePluginDialogCallback, this, "");
}


void k_UiHandler::LoadApplicationSettings()
{
	IPluginManager& lr_PluginManager = object_cast<IPluginManager>(mr_ServiceLocator);
	IEnvironment& lr_Environment = object_cast<IEnvironment>(mr_ServiceLocator);

	std::wstring ls_IniFile = lr_Environment.get_AppDataDirectory() + L"Walhall\\Walhall\\" + lr_Environment.get_ModuleFilename() + L".cfg";
	
	wchar_t ls_Buffer[512];
	std::vector<IDirect3D9BasePlugin*> lk_Plugins = lr_PluginManager.get_Plugins();
	for (unsigned int i = 0; i < lk_Plugins.size(); ++i)
	{
		std::vector<IParameter*> lk_Parameters = lk_Plugins[i]->get_ParameterList();
		for (unsigned int k = 0; k < lk_Parameters.size(); ++k)
		{
			IParameter* lr_Param_ = lk_Parameters[k];
			if (::GetPrivateProfileString(lk_Plugins[i]->get_Name().c_str(), lr_Param_->get_Name().c_str(), L"", ls_Buffer, 512, ls_IniFile.c_str()) > 0)
				lr_Param_->FromString(std::wstring(ls_Buffer));
		}

		::GetPrivateProfileString(lk_Plugins[i]->get_Name().c_str(), L"Active", L"", ls_Buffer, 512, ls_IniFile.c_str());
		lk_Plugins[i]->set_Active(std::wstring(ls_Buffer) == L"true");
	}
}


void k_UiHandler::BuildPluginSpecificDialog(IDirect3D9BasePlugin* ar_Plugin_, TwBar* ar_Bar_)
{
	USES_CONVERSION;

	// Build...
	std::vector<IParameter*> lk_Parameters = ar_Plugin_->get_ParameterList();

	for (unsigned int i = 0; i < lk_Parameters.size(); ++i)
	{
		IParameter* lr_Param_ = lk_Parameters[i];
		std::string ls_ParamName = W2A(lr_Param_->get_Name().c_str());

		switch (lr_Param_->get_ParameterType())
		{
			case r_ParameterType::Slider:
				{
					ISliderParameter* lr_SlideParam_ = object_cast<ISliderParameter>(lr_Param_);
					
					char buf[128];
					sprintf(buf, " min=%d max=%d label=\"%s\"", lr_SlideParam_->get_MinValue(), lr_SlideParam_->get_MaxValue(), W2A(lr_Param_->get_DisplayText().c_str()));
					::TwAddVarCB(ar_Bar_, ls_ParamName.c_str(), TW_TYPE_INT32, k_UiHandler::SetSliderCallback, k_UiHandler::GetSliderCallback, lr_SlideParam_, buf);
				}
				break;
			case r_ParameterType::EditBox:
				{
					IEditBoxParameter* lr_EditParam_ = object_cast<IEditBoxParameter>(lr_Param_);
					::TwAddVarCB(ar_Bar_, ls_ParamName.c_str(), TW_TYPE_STDSTRING, k_UiHandler::SetEditBoxCallback, k_UiHandler::GetEditBoxCallback, lr_EditParam_, "");
				}
				break;
			case r_ParameterType::CheckBox:
				{
					ICheckBoxParameter* lr_CheckParam_ = object_cast<ICheckBoxParameter>(lr_Param_);

					::TwAddButton(ar_Bar_, ls_ParamName.c_str(), k_UiHandler::SetCheckBoxCallback, lr_Param_, "");
					UpdateCheckBoxText(lr_Param_);
				}
				break;
		}
	}

	::TwAddSeparator(ar_Bar_, "", "");
	::TwAddButton(ar_Bar_, "Active", k_UiHandler::TogglePluginCallback, ar_Plugin_, "");
	::TwAddButton(ar_Bar_, "Reset plugin options", k_UiHandler::ResetPluginCallback, ar_Plugin_, "");
	::TwAddButton(ar_Bar_, "Close plugin options", k_UiHandler::HidePluginCallback, ar_Plugin_, "");

	UpdateActiveText(ar_Plugin_);
}


void TW_CALL k_UiHandler::TogglePluginCallback(void* clientData)
{ 
	IDirect3D9BasePlugin* lr_Plugin_ = static_cast<IDirect3D9BasePlugin*>(clientData);
	IEnvironment& lr_Environment = object_cast<IEnvironment>(*k_UiHandler::ms_ServiceLocator);
	std::wstring ls_LogFile = lr_Environment.get_ModulePath()+L"Walhall.log";

	try
	{
		lr_Plugin_->set_Active(!lr_Plugin_->get_Active());
	}
	catch (Exception& e)
	{
		PrintLog(ls_LogFile, L"Fatal Error: set_Active of " << lr_Plugin_->get_Name() << L" failed. \n");
		PrintLog(ls_LogFile, e.GetMessage() << L"\n");
	}

	

	UpdateActiveText(clientData);
}


void TW_CALL k_UiHandler::ShowPluginCallback(void* clientData)
{ 
	IDirect3D9BasePlugin* lr_Plugin_ = static_cast<IDirect3D9BasePlugin*>(clientData);

	USES_CONVERSION;
	std::string ls_ItemText = W2A(std::wstring(lr_Plugin_->get_Name() + L"Options").c_str());
	ls_ItemText = std::string(" ") + ls_ItemText + std::string(" show ");
	::TwDefine(ls_ItemText.c_str());
}


void TW_CALL k_UiHandler::HidePluginCallback(void* clientData)
{ 
	IDirect3D9BasePlugin* lr_Plugin_ = static_cast<IDirect3D9BasePlugin*>(clientData);

	USES_CONVERSION;
	std::string ls_ItemText = W2A(std::wstring(lr_Plugin_->get_Name() + L"Options").c_str());
	ls_ItemText = std::string(" ") + ls_ItemText + std::string(" hide ");
	::TwDefine(ls_ItemText.c_str());
}


void TW_CALL k_UiHandler::ResetPluginCallback(void* clientData)
{ 
	IDirect3D9BasePlugin* lr_Plugin_ = static_cast<IDirect3D9BasePlugin*>(clientData);

	std::vector<IParameter*> lk_Parameters = lr_Plugin_->get_ParameterList();
	for (unsigned int i = 0; i < lk_Parameters.size(); ++i)
	{
		IParameter* lr_Param_ = lk_Parameters[i];
		lr_Param_->ResetToDefault();
	}
}


void TW_CALL k_UiHandler::ClosePluginDialogCallback(void* clientData)
{ 
	k_UiHandler* lk_UiHandler_ = static_cast<k_UiHandler*>(clientData);
	lk_UiHandler_->Close();
}


void TW_CALL k_UiHandler::SaveSettingsDialogCallback(void* clientData)
{
	k_UiHandler* lk_UiHandler_ = static_cast<k_UiHandler*>(clientData);

	IPluginManager& lr_PluginManager = object_cast<IPluginManager>(lk_UiHandler_->get_ServiceLocator());
	IEnvironment& lr_Environment = object_cast<IEnvironment>(lk_UiHandler_->get_ServiceLocator());

	std::wstring ls_IniFile = lr_Environment.get_AppDataDirectory() + L"Walhall\\Walhall\\" + lr_Environment.get_ModuleFilename() + L".cfg";

	std::vector<IDirect3D9BasePlugin*> lk_Plugins = lr_PluginManager.get_Plugins();
	for (unsigned int i = 0; i < lk_Plugins.size(); ++i)
	{
		::WritePrivateProfileString(lk_Plugins[i]->get_Name().c_str(), L"Active", lk_Plugins[i]->get_Active() ? L"true" : L"false", ls_IniFile.c_str());
		
		std::vector<IParameter*> lk_Parameters = lk_Plugins[i]->get_ParameterList();
		for (unsigned int k = 0; k < lk_Parameters.size(); ++k)
		{
			IParameter* lr_Param_ = lk_Parameters[k];
			::WritePrivateProfileString(lk_Plugins[i]->get_Name().c_str(), lr_Param_->get_Name().c_str(), lr_Param_->ToString().c_str(), ls_IniFile.c_str());
		}
	}
}


void TW_CALL k_UiHandler::SetSliderCallback(const void *value, void *clientData)
{
	ISliderParameter* lr_Slider_ = static_cast<ISliderParameter*>(clientData);
	lr_Slider_->set_CurrentValue(*static_cast<const int *>(value));
}


void TW_CALL k_UiHandler::GetSliderCallback(void *value, void *clientData)
{
	ISliderParameter* lr_Slider_ = static_cast<ISliderParameter*>(clientData);
	*static_cast<int *>(value) = lr_Slider_->get_CurrentValue();
}

void TW_CALL k_UiHandler::SetEditBoxCallback(const void *value, void *clientData)
{
	IEditBoxParameter* lr_EditBox_ = static_cast<IEditBoxParameter*>(clientData);

	USES_CONVERSION;
	std::string ls_DataA = *static_cast<const std::string *>(value);
	std::wstring ls_DataW = A2W(ls_DataA.c_str());

	lr_EditBox_->set_CurrentValue(ls_DataW);
}


void TW_CALL k_UiHandler::GetEditBoxCallback(void *value, void *clientData)
{
	IEditBoxParameter* lr_EditBox_ = static_cast<IEditBoxParameter*>(clientData);

	USES_CONVERSION;
	std::string ls_DataA = W2A(lr_EditBox_->get_CurrentValue().c_str());

	*static_cast<std::string *>(value) = ls_DataA;
}


void TW_CALL k_UiHandler::SetCheckBoxCallback(void *clientData)
{
	IParameter* lr_Param_ = static_cast<IParameter*>(clientData);
	ICheckBoxParameter* lr_CheckBox_ = object_cast<ICheckBoxParameter>(lr_Param_);
	lr_CheckBox_->set_CurrentValue(!lr_CheckBox_->get_CurrentValue());

	UpdateCheckBoxText(clientData);
}


void k_UiHandler::UpdateCheckBoxText(void *clientData)
{
	IParameter* lr_Param_ = static_cast<IParameter*>(clientData);
	ICheckBoxParameter* lr_CheckBox_ = object_cast<ICheckBoxParameter>(lr_Param_);

	USES_CONVERSION;
	std::string ls_ParamName = W2A(lr_Param_->get_Name().c_str());
	std::string ls_Text = W2A(lr_Param_->get_DisplayText().c_str());
	std::string ls_BarName = W2A(std::wstring(lr_Param_->get_Owner()->get_Name() + L"Options").c_str());

	std::string ls_Data = ls_BarName + "/" +ls_ParamName + " label=\"" + ls_Text + "\"";
	::TwDefine(ls_Data.c_str());
}


void k_UiHandler::UpdateActiveText(void *clientData)
{
	IDirect3D9BasePlugin* lr_Plugin_ = static_cast<IDirect3D9BasePlugin*>(clientData);

	USES_CONVERSION;
	std::string ls_BarName = W2A(std::wstring(lr_Plugin_->get_Name() + L"Options").c_str());
	std::string ls_Text = "Active: " + std::string(lr_Plugin_->get_Active() ? "true" : "false");
	std::string ls_Data = ls_BarName + "/Active label=\"" + ls_Text + "\"";
	::TwDefine(ls_Data.c_str());

	ls_Data = ls_BarName + " color=\"";
	ls_Data += lr_Plugin_->get_Active() ? "0 64 0" : "64 0 0";
	ls_Data += "\"";
	::TwDefine(ls_Data.c_str());
}
